package com.fxd.util;

import com.fxd.conn.JedisConnUtil;
import redis.clients.jedis.BitOP;
import redis.clients.jedis.BitPosParams;
import redis.clients.jedis.Jedis;

/**
 * 位图工具类
 */
public class BitMapUtil {

    private BitMapUtil() {

    }

    /**
     * 使用场景：
     * 1 日期作为主键，偏移位作为用户id，用于存储日期时间内活跃的用户
     * 2 用户id作为主键，日期天数作为偏移位，用于存储用户在日期时间内的活跃天数
     * 注意事项：
     *
     * @param key   主键
     * @param index 偏移位
     * @param flag  true=1，false=0
     * @return 注意:返回并不是是否存储成功，而是存储在 offset 偏移位的原始值
     */
    public static boolean setBit(String key, long index, boolean flag) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.setbit(key, index, flag);
    }

    /**
     * 对 key 所储存的字符串值，获取指定偏移量上的位(bit)。
     * 当 offset 比字符串值的长度大，或者 key 不存在时，返回 0
     *
     * @param key   主键
     * @param index 偏移位
     * @return
     */
    public static boolean getBit(String key, long index) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.getbit(key, index);
    }

    /**
     * @param key 主键
     * @return 被设置为 1 的位的数量
     */
    public static long bitCount(String key) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitcount(key);
    }

    /**
     * @param key   主键
     * @param start 偏移字节开始位置，单位(byte)
     * @param end   偏移字节结算位置，单位(byte)
     * @return 被设置为 1 的位的数量
     */
    public static long bitCount(String key, long start, long end) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitcount(key, start, end);
    }

    /**
     * 注意事项：
     * 1 如果我们在空字符串或者0字节的字符串里面查找bit为1的内容，那么结果将返回-1。
     * 2 如果我们在字符串里面查找bit为0而且字符串只包含1的值时，将返回字符串最右边的
     * 第一个空位。如果有一个字符串是三个字节的值为0xff的字符串，那么命令BITPOS key 0
     * 将会返回24，因为0-23位都是1。
     * 3 基本上，我们可以把字符串看成右边有无数个0。
     * 4 然而，如果你用指定start和end范围进行查找指定值时，如果该范围内没有对应值，结果将返回-1。
     *
     * @param key  主键
     * @param flag true=1，false=0
     * @return 返回字符串里面第一个被设置为1或者0的bit位
     */
    public static long bitPos(String key, boolean flag) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitpos(key, flag);
    }

    /**
     * @param key   主键
     * @param flag  true=1，false=0
     * @param start 偏移字节开始位置，单位(byte)
     * @return 返回字符串里面第一个被设置为1或者0的bit位
     */
    public static long bitPos(String key, boolean flag, long start) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitpos(key, flag, new BitPosParams(start));
    }

    /**
     * @param key   主键
     * @param flag  true=1，false=0
     * @param start 偏移字节开始位置，单位(byte)
     * @param end   偏移字节结束位置，单位(byte)
     * @return 返回字符串里面第一个被设置为1或者0的bit位
     */
    public static long bitPos(String key, boolean flag, long start, long end) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitpos(key, flag, new BitPosParams(start, end));
    }

    /**
     * 对一个或多个保存二进制位的字符串 key 进行位元操作，并将结果保存到 destkey 上。
     * 当 BITOP 处理不同长度的字符串时，较短的那个字符串所缺少的部分会被看作 0 。
     * 空的 key 也被看作是包含 0 的字符串序列。
     *
     * @param bitOP     位运算符
     * @param destKey   运算后的值的所在的key
     * @param readyKeys 准备进行位运算的key集合
     * @return 保存到 destKey 的字符串的长度，和输入 key 中最长的字符串长度相等
     */
    public static long bitop(BitOP bitOP, String destKey, String... readyKeys) {
        Jedis jedis = JedisConnUtil.getJedis();
        return jedis.bitop(bitOP, destKey, readyKeys);
    }

}
